﻿/*
Transform Plugin
Copyright (c) 2009 DAER Systems (daersystems.com)
Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html)
and MIT (http://www.opensource.org/licenses/mit-license.php) licenses.
  
2010.06.07 RA add cache xsl and xml
*/


(function ($) {
    var transform_cache_xsl = new Array(); //RA
    var transform_cache_xml = new Array(); //RA

    $.transform_cache_set_xml = function (xml_, str_) { transform_cache_xml[xml_] = str_; }
    $.transform_cache_set_xsl = function (xsl_, str_) { transform_cache_xsl[xsl_] = str_; }

    $.transform_cache_del_xml = function (xml_) { transform_cache_xml[xml_] = null; }
    $.transform_cache_del_xsl = function (xsl_) { transform_cache_xsl[xsl_] = null; }

    $.transform = function (o) {
        var createXmlObj = function (data) {
            if ($.browser.msie) {
                var x = $("<xml>")[0];
                x.loadXML(data);
                return x;
            } else {
                var parser = new DOMParser();
                return parser.parseFromString(data, "text/xml");
            }
        };

        var call = function (f, o, tel, other) {
            if ($.isFunction(f)) {
                var arg1 = tel.html();
                if (o.c.dataType.toUpperCase() == "JSON") {
                    try {
                        arg1 = eval("(" + tel.text() + ")");
                    } catch (ex) {
                        arg1 = { error: "An error occurred while converting HTML to JSON" };
                    }
                }
                if (o.c.dataType.toUpperCase() == "XML") {
                    arg1 = createXmlObj(tel.html());
                }

                try { f.apply(o.c, [arg1, o.c.xslstr, o.c.xmlstr, o.c, other]); } catch (ex) { }
            }
        };

        var t = this;

        t.c = {
            cache: false,
            cacheXsl: false, //RA
            cacheXml: false, //RA
            cacheNetXsl: true, //RA
            cacheNetXml: false, //RA      
            async: true,
            xsl: false,
            xml: false,
            xmlAddToDOM: false, //RA
            xslstr: false,
            xmlstr: false,
            xslobj: false,
            xmlobj: false,
            xslParams: false,
            error: false,
            success: false,
            complete: false,
            island: false,
            pass: false,
            msg: false,
            dataType: "html"
        };
        $.extend(t.c, o);

        t.c.xslPath = t.c.xsl;
        //RA
        if (t.c.cache == true) {
            t.c.cacheXml = true;
            t.c.cacheXsl = true;
        }
        if (t.c.cacheXsl == true && transform_cache_xsl[t.c.xsl] != null) {
            t.c.xslstr = transform_cache_xsl[t.c.xsl];
            t.c.xsl = false;
        }
        if (t.c.cacheXml == true && transform_cache_xml[t.c.xml] != null) {
            t.c.xmlstr = transform_cache_xml[t.c.xml];
            t.c.xml = false;
        }

        if (o.msg) {
            $(o.el).html((typeof (o.msg) == "string") ? o.msg : $(o.msg).html());
        }

        var id = function (pre) {
            var name = pre + "_" + (Math.round(Math.random() * 999));
            return $("#" + name).length === 0 ? name : id(pre);
        };

        var replaceref = function (val, o) {
            o.c.xslPath = o.c.xslPath ? o.c.xslPath : "";
            var c = location.protocol == "file:" && $.browser.msie ? "\\" : "/";
            var path1 = location.protocol + c + c + location.host;
            var path2 = location.pathname.substring(0, location.pathname.lastIndexOf(c) + 1) + o.c.xslPath.substring(0, o.c.xslPath.lastIndexOf("/") + 1);

            var res = '';
            if (val.substring(0, 1) == c) {
                res = path1 + val;
            }
            else if (val.substring(0, 2) == "..") {
                var count = 0;
                while (val.indexOf("..") != -1) {
                    val = val.substring(val.indexOf("..") + 3);
                    count += 1;
                }

                var p = path1 + path2.substring(0, path2.length - 1);

                for (var x = 0; x < count; x++) {
                    p = p.substring(0, p.lastIndexOf(c));
                }
                res = p + c + val;
            }
            /*Begin RA*/
            else if (val.substring(0, 7) == "http://" || val.substring(0, 8) == "https://") {
                res = val;
            }
            else if (val.substring(0, 2) == "./") {
                res = path1 + o.c.xslPath.substring(0, o.c.xslPath.lastIndexOf("/") + 1) + val.substring(2, val.length);
            }
            /*End RA*/
            else {
                res = path1 + path2 + val;
            }
            if (!o.c.cacheNetXsl) {
                res += '?_' + new Date().getTime().toString();
            }
            return res;
        };

        var checkReady = function (o) {
            if ((o.c.xslstr || o.c.xslobj) && (o.c.xmlstr || o.c.xmlobj)) {
                var fail = false;
                var tel = $("<div>");
                if (o.c.throwerror) {
                    call(o.c.error, o, tel, { message: "Bad XML or XSL call" });
                    return;
                }

                if (o.c.island) {
                    if (o.c.island === true) { o.c.island = "body"; }
                    o.c.xslid = id("xsl");
                    $(o.c.island).append("<div id='" + o.c.xslid + "' name='" + o.c.xslid + "' style='display:none;'>" + o.c.xslstr + "</div>");
                    o.c.xmlid = id("xml");
                    $(o.c.island).append("<div id='" + o.c.xmlid + "' name='" + o.c.xmlid + "' style='display:none;'>" + o.c.xmlstr + "</div>");
                }

                o.c.xslobj = o.c.xslobj ? o.c.xslobj : createXmlObj(o.c.xslstr);
                var tmp_str = o.c.xmlstr;
                //add info to XML DOM
                if (o.c.xmlAddToDOM !== false) {
                    var nom = tmp_str.search('>');
                    if (nom >= 0) {
                        var s_left = tmp_str.substr(0, nom + 1);
                        var s_right = tmp_str.substr(nom + 1, tmp_str.length);
                        tmp_str = s_left + o.c.xmlAddToDOM + s_right;
                    }
                }
                o.c.xmlobj = o.c.xmlobj ? o.c.xmlobj : createXmlObj(tmp_str);

                var fixref, addparams;
                if ($.browser.msie) {
                    try {

                        fixref = function (ref, xObj) {
                            var vals = xObj.selectNodes(ref);
                            for (var x = 0; x < vals.length; x++) {
                                vals[x].setAttribute("href", replaceref(vals[x].getAttribute("href"), o));
                            }
                        };

                        fixref("//xsl:include", o.c.xslobj);
                        fixref("//xsl:import", o.c.xslobj);

                        addparams = function (op, xObj) {
                            for (var p in op) {
                                var strParam = "//xsl:param[@name='" + p + "']";

                                try {
                                    var v = op[p];
                                    if (typeof v === "boolean") {
                                        v = "'" + v + "'";
                                    } else {
                                        if (isNaN(parseInt(v)) && v.indexOf("'") < 0) {
                                            v = "'" + v + "'";
                                        }
                                    }
                                    var xslParam = xObj.selectSingleNode(strParam);
                                    if (xslParam == null) {
                                        var newparam = xObj.createElement("xsl:param");
                                        newparam.setAttribute("name", p);
                                        xObj.documentElement.insertBefore(newparam, xObj.selectSingleNode("//xsl:template"));
                                        xslParam = xObj.selectSingleNode(strParam);
                                    }
                                    xslParam.setAttribute("select", v);
                                } catch (ex) {
                                    //param failed
                                }
                            }
                        };
                        if (o.c.xslParams) {
                            addparams(o.c.xslParams, o.c.xslobj);
                            o.c.xslobj = createXmlObj(o.c.xslobj.xml); //reload xml
                        }
                        tel.empty().html(o.c.xmlobj.transformNode(o.c.xslobj));
                    } catch (ex) {
                        fail = true;
                        call(o.c.error, o, tel, ex);
                    }
                } else {
                    try {
                        var proc = new XSLTProcessor();

                        var childNodes = function (obj, find) {
                            var cns = [];
                            var objs = obj.getElementsByTagName(find);
                            for (var x = 0; x < objs.length; x++) {
                                if (objs[x].parentNode == obj) {
                                    cns[cns.length] = objs[x];
                                }
                            }

                            return cns;
                        };

                        var safariimportincludefix = function (xObj, rootConfig) {
                            var vals = $.merge($.makeArray(xObj.getElementsByTagName("import")), $.makeArray(xObj.getElementsByTagName("include")));

                            for (var x = 0; x < vals.length; x++) {
                                var node = vals[x];
                                $.ajax({
                                    passData: { node: node, xObj: xObj, rootConfig: rootConfig },
                                    dataType: "xml",
                                    async: false,
                                    url: replaceref(node.getAttribute("href"), rootConfig),
                                    success: function (xhr) {
                                        try {
                                            var _ = this.passData;
                                            xhr = safariimportincludefix(xhr, _.rootConfig);

                                            var imports = $.merge(childNodes(xhr.getElementsByTagName("stylesheet")[0], "param"), childNodes(xhr.getElementsByTagName("stylesheet")[0], "template"));

                                            var existingNodes = $.merge(childNodes(_.xObj.getElementsByTagName("stylesheet")[0], "param"), childNodes(_.xObj.getElementsByTagName("stylesheet")[0], "template"));
                                            var existingNames = [];
                                            var existingMatches = [];
                                            for (var a = 0; a < existingNodes.length; a++) {
                                                if (existingNodes[a].getAttribute("name")) {
                                                    existingNames[existingNodes[a].getAttribute("name")] = true;
                                                } else {
                                                    existingMatches[existingNodes[a].getAttribute("match")] = true;
                                                }
                                            }

                                            var pn = _.node.parentNode;
                                            for (var y = 0; y < imports.length; y++) {
                                                if (!existingNames[imports[y].getAttribute("name")] && !existingMatches[imports[y].getAttribute("match")]) {
                                                    var clonednode = _.xObj.importNode(imports[y], true);
                                                    pn.insertBefore(clonednode, _.xObj.getElementsByTagName("template")[0]);
                                                }
                                            }
                                            pn.removeChild(_.node);
                                        } catch (ex) {

                                        }
                                    }
                                });
                            }

                            return xObj;
                        };

                        fixref = function (ref, xObj) {
                            ref = $.browser.mozilla && $.browser.version.substring(0, 3) == "1.9" ? "xsl:" + ref : ref;
                            var vals = xObj.getElementsByTagName(ref);
                            for (var x = 0; x < vals.length; x++) {
                                vals[x].setAttribute("href", replaceref(vals[x].getAttribute("href"), o));
                            }
                        };

                        if ($.browser.safari) {
                            o.c.xslobj = safariimportincludefix(o.c.xslobj, o);
                        } else {
                            fixref("import", o.c.xslobj);
                            fixref("include", o.c.xslobj);
                        }

                        addparams = function (op) {
                            for (var p in op) {
                                try { proc.setParameter(null, p, op[p]); } catch (ex) { }
                            }
                        };
                        addparams(o.c.xslParams);

                        var doc = document.implementation.createDocument("", "", null);
                        proc.importStylesheet(o.c.xslobj);
                        tel.empty().append(proc.transformToFragment(o.c.xmlobj, doc));
                    } catch (ex) {
                        fail = true;
                        call(o.c.error, o, tel, ex);
                    }
                }

                if (o.c.el) {
                    if (tel.html()) { $(o.c.el).html(tel.html()); }
                }
                if (!fail) {
                    call(o.c.success, o, tel);
                }
                call(o.c.complete, o, tel);

                return tel.html();
            }
        };

        var makeCall = function (t, options, type, cache) {
            if (typeof (options) == "string") {
                options = {
                    cache: cache, //false,//RA
                    url: options,
                    dataType: "xml",
                    async: t.c.async,
                    pass: t.c.pass
                };
            }

            options.complete = function (r, s) {
                if (s != "success") {
                    if (!t.c.threwError) {
                        t.c.threwError = true;
                        call(t.c.error, t, $("<div>" + r.responseText + "</div>"), { message: "Error requesting file " + this.url });
                        call(t.c.complete, t, $("<div>" + r.responseText + "</div>"));
                    }
                    return;
                }

                if (type == "XSL") {
                    if (r.status == 200) { t.c.xslstr = r.responseText; } else { t.c.xslstr = "error"; t.c.throwerror = true; }
                    //RA
                    if (t.c.cacheXsl == true) {
                        transform_cache_xsl[t.c.xsl] = t.c.xslstr;
                    }
                }
                else {
                    if (r.status == 200) { t.c.xmlstr = r.responseText; } else { t.c.xmlstr = "error"; t.c.throwerror = true; }
                    //RA
                    if (t.c.cacheXml == true) {
                        transform_cache_xml[t.c.xml] = t.c.xmlstr;
                    }
                }
                if (t.c.async) { checkReady(t); }
            };

            $.ajax(options);
        };

        if (t.c.xsl) {
            makeCall(t, o.xsl, "XSL", t.c.cacheNetXsl);
        }

        if (t.c.xml) {
            makeCall(t, o.xml, "XML", t.c.cacheNetXml);
        }

        if (!t.c.async || (t.c.xmlstr || t.c.xmlobj) || (t.c.xslstr || t.c.xslobj)) {
            return checkReady(t);
        }
    };

    $.fn.transform = function (o) {
        return this.each(function () {
            o = o ? o : {};
            o.el = this;
            var t = new $.transform(o);
        });
    };
})(jQuery);

/*$().ready(function() {
$("[transform]").each(function(num,el) {
$(el).transform(eval("(" + $(el).attr("transform") + ")"));
});
	
});*/